package dv.apkeep;

import dv.network.Device;
import dv.network.Port;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;

import java.util.HashSet;

public class DeltaForwardingGraph {
    public Graph<Device, ECEdge> graph;
    public HashSet<Integer> transferredPreds;

    public DeltaForwardingGraph(HashSet<Integer> transferredPreds, Model model) {
        this.graph = new DefaultDirectedGraph<>(ECEdge.class);
        this.transferredPreds = transferredPreds; // TODO: clone? consider concurrency!

        for (int delta : transferredPreds) {
            for (Port port : model.predToPorts.get(delta)) {
                Device device = port.getDevice();
                if (!this.graph.containsVertex(device)) {
                    this.graph.addVertex(device);
                }
                if (port.getPeer() == null) {
                    continue;
                }
                Device peerDevice = port.getPeer().getDevice();
                if (!this.graph.containsVertex(peerDevice)) {
                    this.graph.addVertex(peerDevice);
                }

                if (!this.graph.containsEdge(device, peerDevice)) {
                    ECEdge edge = new ECEdge(device, peerDevice);
                    edge.addPredicate(delta);
                    this.graph.addEdge(device, peerDevice, edge);
                } else {
                    ECEdge edge = this.graph.getEdge(device, peerDevice);
                    edge.addPredicate(delta);
                }
            }
        }
    }

    public class ECEdge extends DefaultEdge {
        private Device from;
        private Device to;
        private HashSet<Integer> predicates;

        public ECEdge(Device from, Device to) {
            this.from = from;
            this.to = to;
            this.predicates = new HashSet<>();
        }

        public void addPredicate(int predicate) {
            this.predicates.add(predicate);
        }

        public HashSet<Integer> getPredicates() {
            return predicates;
        }

        public Device getFrom() {
            return from;
        }

        public Device getTo() {
            return to;
        }
    }
}
